/*
 * #%L
 * SwiftUICommonUtilities
 * $Id:$
 * $HeadURL:$
 * %%
 * Copyright (C) 2011 - 2012 Linkwithweb
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public 
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>.
 * #L%
 */
/**
 * 
 */
package com.linkwithweb.products.swiftui.utils;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.test.jdbc.SimpleJdbcTestUtils;

import com.mysql.management.MysqldResource;
import com.mysql.management.MysqldResourceI;

/**
 * Manages the life cycle of the embedded MySQL database.
 * This manager uses the MySQL Connector/MXJ and Mysql Connector/J JDBC driver to manage the
 * embedded MySQL DB instance.
 *
 * @see http://dev.mysql.com/doc/refman/5.1/en/connector-mxj.html for more details
 */
/**
 * @author ashwin kumar
 * 
 */

public class EmbeddedMysqlManager {
	protected Logger logger = LoggerFactory.getLogger(this.getClass());

	private MysqldResource mysqldResource;
	private String baseDatabaseDir = System.getProperty("java.io.tmpdir");
	private String databaseName = "test_db_" + System.nanoTime();
	private int port = 13306;
	private String username = "root";
	private String password = "password";
	private List<String> sqlScripts = new ArrayList<String>();
	private DriverManagerDataSource datasource;

	public EmbeddedMysqlManager() {
	}

	// -------------------------------------------------------------------------
	/**
	 * Starts the mysql database
	 * 
	 * @return
	 */
	public void startDatabase() {
		if (logger.isDebugEnabled()) {
			logger.debug("=============== Starting Embedded MySQL using these parameters ===============");
			logger.debug("baseDatabaseDir : " + baseDatabaseDir);
			logger.debug("databaseName : " + databaseName);
			logger.debug("host : localhost (hardcoded)");
			logger.debug("port : " + port);
			logger.debug("username : " + username);
			logger.debug("password : " + password);
			logger.debug("=============================================================================");
		}

		File databaseDir = new File(new File(baseDatabaseDir), databaseName);

		mysqldResource = new MysqldResource(databaseDir);

		Map<String, String> database_options = new HashMap<String, String>();
		database_options.put(MysqldResourceI.PORT, Integer.toString(port));
		database_options.put(MysqldResourceI.INITIALIZE_USER, "true");
		database_options.put(MysqldResourceI.INITIALIZE_USER_NAME, username);
		database_options.put(MysqldResourceI.INITIALIZE_PASSWORD, password);

		mysqldResource.start("embedded-mysqld-thread-" + System.currentTimeMillis(), database_options);

		if (!mysqldResource.isRunning()) {
			throw new RuntimeException("MySQL did not start.");
		}

		/**
		 * Make sure DB is shutdown on JVM Exit.. So that no resources are
		 * locked
		 */
		LinkWithwebShutdownHook shutdownHook = new LinkWithwebShutdownHook();
		shutdownHook.setMysqldResource(mysqldResource);
		Runtime.getRuntime().addShutdownHook(shutdownHook);

		logger.info("MySQL started successfully @ " + System.currentTimeMillis());

		try {
			if (!sqlScripts.isEmpty()) {
				SimpleJdbcTemplate simpleJdbcTemp = new SimpleJdbcTemplate(getDatasource());
				logger.info("Executing scripts...");
				int dataCount = 0;

				try {
					dataCount = simpleJdbcTemp.queryForInt("SELECT count(*) FROM FRM_USERS");
				} catch (Exception e) {
					// TODO: handle exception
				}

				if (dataCount == 0) {
					for (String script : sqlScripts) {
						logger.info("Executing script [" + script + "]");
						SimpleJdbcTestUtils.executeSqlScript(simpleJdbcTemp, new ClassPathResource(script), false);
					}
				}
			} else {
				logger.info("No scripts to load...");
			}
		} catch (Exception e) {
			e.printStackTrace();
			logger.error(e.getMessage(), e);
			if ((mysqldResource != null) && (mysqldResource.isRunning())) {
				shutdownDatabase();
			}
		}

	}

	public void shutdownDatabase() {
		mysqldResource.shutdown();
		if (mysqldResource.isRunning() == false) {
			logger.info(">>>>>>>>>> DELETING MYSQL BASE DIR [" + mysqldResource.getBaseDir() + "] <<<<<<<<<<");
			try {
				// FileUtils.forceDelete(mysqldResource.getBaseDir());
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
			}
		}
	}

	/**
	 * Gets a {@link DataSource} for the embedded DB managed by this manager
	 * 
	 * @return
	 */
	public DataSource getDatasource() {
		if (!mysqldResource.isRunning()) {
			logger.error("MySQL instance not found... Terminating");
			throw new RuntimeException("Cannot get Datasource, MySQL instance not started.");
		}

		if (datasource == null) {
			datasource = new DriverManagerDataSource();
			datasource.setDriverClassName("com.mysql.jdbc.Driver");
			String url = "jdbc:mysql://localhost:" + port + "/" + databaseName + "?useUnicode=yes&characterEncoding=UTF-8&"
					+ "createDatabaseIfNotExist=true&sessionVariables=FOREIGN_KEY_CHECKS=0";

			datasource.setUrl(url);
			datasource.setUsername(username);
			datasource.setPassword(password);
		}
		return datasource;
	}

	// -------------------------------------------------------------------------
	/**
	 * @return the baseDatabaseDir
	 */
	public final String getBaseDatabaseDir() {
		return baseDatabaseDir;
	}

	/**
	 * @param baseDatabaseDir
	 *            the baseDatabaseDir to set
	 */
	public final void setBaseDatabaseDir(String baseDatabaseDir) {
		this.baseDatabaseDir = baseDatabaseDir;
	}

	/**
	 * @return the databaseName
	 */
	public final String getDatabaseName() {
		return databaseName;
	}

	/**
	 * @param databaseName
	 *            the databaseName to set
	 */
	public final void setDatabaseName(String databaseName) {
		this.databaseName = databaseName;
	}

	/**
	 * @return the port
	 */
	public final int getPort() {
		return port;
	}

	/**
	 * @param port
	 *            the port to set
	 */
	public final void setPort(int port) {
		this.port = port;
	}

	/**
	 * @return the username
	 */
	public final String getUsername() {
		return username;
	}

	/**
	 * @param username
	 *            the username to set
	 */
	public final void setUsername(String username) {
		this.username = username;
	}

	/**
	 * @return the password
	 */
	public final String getPassword() {
		return password;
	}

	/**
	 * @param password
	 *            the password to set
	 */
	public final void setPassword(String password) {
		this.password = password;
	}

	/**
	 * @return the sqlScripts
	 */
	public final List<String> getSqlScripts() {
		return sqlScripts;
	}

	/**
	 * @param sqlScripts
	 *            the sqlScripts to set
	 */
	public final void setSqlScripts(List<String> sqlScripts) {
		this.sqlScripts = sqlScripts;
	}
}
